/********************************** (C) COPYRIGHT *******************************
 * File Name          : flashop.c
 * Author             : RVMaking
 * Version            : V1.0.0
 * Date               : 2022/08/01
 * Description        : single line debug interface
 *********************************************************************************
 * Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
 * Attention: This software (modified or not) and binary are used for 
 * microcontroller manufactured by Nanjing Qinheng Microelectronics.
 *******************************************************************************/

#include "flash_prg_algorithm.h"


//flash operate, run in ram
//init,uninit,erasechip,erasesector,programpage
//add ebreak infront of bin
const uint8_t flash_code[]={
	
		0x02, 0x90, 0x00, 0x00, 0xB7, 0x27, 0x02, 0x40, 0xB7, 0x06, 0x67, 0x45, 0x23, 0xA0, 0x07, 0x00, 
    0x93, 0x86, 0x36, 0x12, 0x37, 0x97, 0xEF, 0xCD, 0xD4, 0xC3, 0x13, 0x07, 0xB7, 0x9A, 0xD8, 0xC3, 
    0xD4, 0xD3, 0xD8, 0xD3, 0x01, 0x45, 0x82, 0x80, 0x37, 0x27, 0x02, 0x40, 0x1C, 0x4B, 0x01, 0x45, 
    0x93, 0xE7, 0x07, 0x08, 0x1C, 0xCB, 0x82, 0x80, 0xB7, 0x27, 0x02, 0x40, 0x98, 0x4B, 0xAD, 0x66, 
    0x37, 0x36, 0x00, 0x40, 0x13, 0x67, 0x47, 0x00, 0x98, 0xCB, 0x98, 0x4B, 0x93, 0x86, 0xA6, 0xAA, 
    0x13, 0x67, 0x07, 0x04, 0x98, 0xCB, 0xD8, 0x47, 0x05, 0x8B, 0x11, 0xE7, 0x98, 0x4B, 0x01, 0x45, 
    0x6D, 0x9B, 0x98, 0xCB, 0x82, 0x80, 0x14, 0xC2, 0xFD, 0xB7, 0xB7, 0x27, 0x02, 0x40, 0x98, 0x4B, 
    0xB7, 0x06, 0x02, 0x00, 0x37, 0x36, 0x00, 0x40, 0x55, 0x8F, 0x98, 0xCB, 0xC8, 0xCB, 0x98, 0x4B, 
    0xAD, 0x66, 0x93, 0x86, 0xA6, 0xAA, 0x13, 0x67, 0x07, 0x04, 0x98, 0xCB, 0xD8, 0x47, 0x05, 0x8B, 
    0x19, 0xE7, 0x98, 0x4B, 0x01, 0x45, 0x13, 0x77, 0xF7, 0xFB, 0x98, 0xCB, 0x82, 0x80, 0x14, 0xC2, 
    0xF5, 0xB7, 0x41, 0x11, 0x2A, 0xC2, 0x02, 0xC4, 0x93, 0x85, 0xF5, 0x03, 0x02, 0xC6, 0x99, 0x81, 
    0x2E, 0xC6, 0x37, 0x27, 0x02, 0x40, 0x1C, 0x4B, 0xC1, 0x66, 0x37, 0x05, 0x08, 0x00, 0xD5, 0x8F, 
    0xAD, 0x66, 0x1C, 0xCB, 0xB7, 0x35, 0x00, 0x40, 0xB7, 0x27, 0x02, 0x40, 0x93, 0x86, 0xA6, 0xAA, 
    0x98, 0x4B, 0x49, 0x8F, 0x98, 0xCB, 0xD8, 0x47, 0x05, 0x8B, 0x3D, 0xE7, 0x12, 0x47, 0xB2, 0x82, 
    0x37, 0x03, 0x04, 0x00, 0x3A, 0xC4, 0x41, 0x47, 0xD8, 0x81, 0x22, 0x47, 0x83, 0xA2, 0x02, 0x00, 
    0x11, 0x06, 0x23, 0x20, 0x57, 0x00, 0x98, 0x4B, 0x33, 0x67, 0x67, 0x00, 0x98, 0xCB, 0xD8, 0x47, 
    0x05, 0x8B, 0x29, 0xE7, 0x22, 0x47, 0xB2, 0x82, 0x11, 0x07, 0x3A, 0xC4, 0x98, 0x81, 0x7D, 0x17, 
    0x13, 0x77, 0xF7, 0x0F, 0xD8, 0x81, 0x71, 0xFB, 0x12, 0x47, 0xD8, 0xCB, 0x98, 0x4B, 0x13, 0x67, 
    0x07, 0x04, 0x98, 0xCB, 0xD8, 0x47, 0x05, 0x8B, 0x05, 0xE7, 0xD8, 0x47, 0x41, 0x8B, 0x1D, 0xC3, 
    0xD8, 0x47, 0xC1, 0x76, 0xFD, 0x16, 0x13, 0x67, 0x07, 0x01, 0xD8, 0xC7, 0x98, 0x4B, 0x05, 0x45, 
    0x75, 0x8F, 0x98, 0xCB, 0x41, 0x01, 0x82, 0x80, 0x94, 0xC1, 0x71, 0xB7, 0x94, 0xC1, 0x45, 0xBF, 
    0x94, 0xC1, 0xC9, 0xBF, 0x12, 0x47, 0x13, 0x07, 0x07, 0x04, 0x3A, 0xC2, 0x32, 0x47, 0x7D, 0x17, 
    0x3A, 0xC6, 0x3D, 0xF7, 0x98, 0x4B, 0xC1, 0x76, 0xFD, 0x16, 0x75, 0x8F, 0x98, 0xCB, 0x01, 0x45, 
    0xD1, 0xBF, 0x51, 0x11, 0x2A, 0xC0, 0x02, 0xC2, 0x8D, 0x05, 0x02, 0xC4, 0x89, 0x81, 0x2E, 0xC4, 
    0x18, 0x42, 0x92, 0x47, 0x93, 0x06, 0x46, 0x00, 0x02, 0x46, 0x8A, 0x07, 0xB2, 0x97, 0x9C, 0x43, 
    0x63, 0x1D, 0xF7, 0x00, 0x92, 0x47, 0x36, 0x86, 0x85, 0x07, 0x3E, 0xC2, 0x12, 0x47, 0xA2, 0x47, 
    0xE3, 0x60, 0xF7, 0xFE, 0x01, 0x45, 0x31, 0x01, 0x82, 0x80, 0x05, 0x45, 0xED, 0xBF, 0x00, 0x00, 
		
};


const program_target_t flash_algo = 
{
		0x20000004, //init
		0x20000028, //uninit
		0x20000038, //erasechip
		0x2000006a, //erasesector
		0x200000a2, //prgpage
		{
			0x20000000, //ebreak
			0x20000800  //sp
		},
		0x20000200,   //buffer addr
		0x20000000,   //algo location in ram
		(sizeof(flash_code)/4), //word size
		flash_code,     
		(1024/4),         //buffer size (words)  	
};


uint8_t flash_syscall_exec( const prggram_syscall_t *syscall_param, uint32_t entry, uint32_t arg1, uint32_t arg2, uint32_t arg3,uint32_t arg4) 
{
		uint8_t ack=0,i=0;
		uint32_t s=0;
		ack = SingleLineWriteGPR(10,arg1);  //a0 = arg1
		if(ack) return 1;
		ack = SingleLineWriteGPR(11,arg2);  //a1 = arg2
		if(ack) return 2;
		ack = SingleLineWriteGPR(12,arg3);  //a2 = arg3
		if(ack) return 3;
		ack = SingleLineWriteGPR(13,arg4);  //a3 = arg4
		if(ack) return 4;
		ack = SingleLineWriteGPR(2,syscall_param->stackpoint); //set sp
	  if(ack) return 5;
		ack = SingleLineWriteGPR(1,syscall_param->breakpoint); //set ra = breakpoint	
		if(ack) return 6;
	  ack = SingleLineWriteCSR(0x7b1, entry); //set dpc = entry
		if(ack) return 7;
		ack = SingleLineWriteCSR(0x7b0,0x00009603);  //set dcsr, core will enter debug mode,when run 'ebreak'
		if(ack) return 8;	
	
		SingleLineExitPauseMode( );
	
retryrdgpr:
    ack = SingleLineCheckPauseContinue( );
    ack = SingleLineReadGPR(10, &s);  //read a0
    if(ack && (i< 20))
    {
        i++;
        Delay_Ms(1);
        goto retryrdgpr;
    }
		
		if((uint8_t) s) return 0xef;
		
		debug_log("syscall(%08x) return(%x)\r\n",entry,(uint8_t)s);
		
    return 0;
}



uint8_t SingleLine_Flash_Init(void)
{
		uint8_t ack=0;
		ack = SingleLineWriteMEMDirectBlock( flash_algo.algo_start, (uint16_t *)&flash_algo.algo_size, (uint32_t *)flash_algo.algo_blob );
		if(ack) return ack;	
		ack = flash_syscall_exec(&flash_algo.sys_call_s, flash_algo.init,0,0,0,0);//execute init
		if(ack) return ack;
		return 0;
}


uint8_t SingleLine_Flash_Uninit(void)
{
		uint8_t ack=0;
		ack = flash_syscall_exec(&flash_algo.sys_call_s, flash_algo.uninit,0,0,0,0);//execute init
		if(ack) return ack;
		return 0;
}


uint8_t SingleLine_Flash_ProgramPages(uint32_t addr, uint32_t *buf, uint32_t size)
{
		uint32_t write_size=0; 
		uint8_t ack=0;
		while(size > 0)
		{
			 write_size = size > flash_algo.program_buffer_size ? flash_algo.program_buffer_size : size;
			 ack = SingleLineWriteMEMDirectBlock(flash_algo.program_buffer,(uint16_t *)&write_size, buf );	
			 if(ack) return ack;
			 ack = flash_syscall_exec(&flash_algo.sys_call_s, flash_algo.programpage, addr, flash_algo.program_buffer_size*4, flash_algo.program_buffer, 0 );	
			 if(ack) return ack;
			
			 addr += write_size*4;
			 buf  += (write_size);  //words
			 size -= write_size*4;	
		}
		return 0;
}


uint8_t SingleLine_Flash_EraseSector(uint32_t addr)
{
	  uint8_t ack=0;
		ack = flash_syscall_exec(&flash_algo.sys_call_s, flash_algo.erasesector,addr,0,0,0);
		if(ack) return ack;
		return 0;
}


uint8_t SingleLine_Flash_EraseChip(void)
{
		uint8_t ack=0;
		ack = flash_syscall_exec(&flash_algo.sys_call_s, flash_algo.erasechip,0,0,0,0);
		if(ack) return ack;
		return 0;	
}





